﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GameEngine.PositionConverter;


namespace GameEngine.PDNParser
{
    /// <summary>
    /// FEN Parsing Class
    /// </summary>
    public class FENParser
    {
        private StringBuilder _sb;
        private IPositionConverter _posConverter;

        public FENParser(enumGameType gameType)
        {
            _posConverter = PositionConverterFactory.Create(gameType);
        }

        /// <summary>
        /// The main API method for parsing FEN
        /// </summary>
        public BitBoard Parse(string sFEN)
        {
            GameBoard gb = new GameBoard(_posConverter.BoardSize);
            gb.CleanBoard();

            string[] parts = sFEN.Split(':');
            if (parts.Length < 2)
                ThrowError("BadFEN");

            // determine who is on move
            if (parts[0] == "W")
                gb.SetOnMove(enumFigureColor.White);
            else if (parts[0] == "B")
                gb.SetOnMove(enumFigureColor.Black);
            else
                ThrowError("BadFEN");

            ParsePositions(parts[1], gb);

            if (parts.Length > 1)
            {
                ParsePositions(parts[2], gb);
            }

            return gb.PackGameBoard();
        }


        /// <summary>
        /// Parses position strip
        /// </summary>
        protected void ParsePositions(string strip, GameBoard gb)
        {
            // determine figure color
            enumFigureColor color = enumFigureColor.White;
            if (strip[0] == 'W')
                color = enumFigureColor.White;
            else if (strip[0] == 'B')
                color = enumFigureColor.Black;
            else
                ThrowError("BadFEN");

            strip = strip.Substring(1, strip.Length - 1);

            string[] parts = strip.Split(',');

            foreach (string p in parts)
            {
                bool bKing = false;
                string pp = p;
                if (pp[0] == 'K')
                {
                    bKing = true;
                    pp = pp.Substring(1, p.Length - 1);
                }

                // parse position
                Position pos;
                if(_posConverter.TryParse(pp, out pos) == false)
                    ThrowError("BadFEN");

                // parse figure type
                enumFigureType figureType = enumFigureType.Nothing;
                if (color == enumFigureColor.White)
                {
                    figureType = bKing == true ? enumFigureType.WhiteKing : enumFigureType.WhiteMan;  
                }
                else
                {
                    figureType = bKing == true ? enumFigureType.BlackKing : enumFigureType.BlackMan;  
                }

                // place figure
                gb.PlaceFigure(pos, figureType);
            }
        }

        #region FEN Writing
        

        /// <summary>
        /// The main API method for writing FEN
        /// </summary>
        public string WriteFEN(GameBoard gm, bool chessNotation = false)
        {
            _sb = new StringBuilder();
            _posConverter = new CzechPositionConverter();

            // write on move
            if (gm.OnMove == enumFigureColor.White)
                _sb.Append("W:");
            else
                _sb.Append("B:");

            // write white figures
            WritePositions(gm, enumFigureColor.White, chessNotation);

            _sb.Append(":");

            // write black figures
            WritePositions(gm, enumFigureColor.Black, chessNotation);

            return _sb.ToString();

        }

        /// <summary>
        /// Writes position of one side
        /// </summary>
        protected void WritePositions(GameBoard gm, enumFigureColor color, bool chessNotation)
        {
            if (color == enumFigureColor.White)
                _sb.Append("W");
            else
                _sb.Append("B");

            for (int row = 0; row < gm.Size; row++)
            {
                for (int col = 0; col < gm.Size; col++)
                {
                    enumFigureType figure = gm.GetField(row, col);
                    if (figure != enumFigureType.Nothing && figure.FigureColor() == color)
                    {
                        WritePosition(new Position(row, col), figure, chessNotation);
                        _sb.Append(",");
                    }
                }
            }

            _sb.Remove(_sb.Length - 1, 1);
        }

        /// <summary>
        /// Writes single figure position
        /// </summary>
        protected void WritePosition(Position pos, enumFigureType figureType, bool chessNotation)
        {
            if (figureType.IsKing())
                _sb.Append("K");
            _sb.Append(_posConverter.PositionToString(pos, true));
        }

        #endregion

        protected void ThrowError (string sKey)
		{
			throw new Exception(sKey);
		}

    }

}
